home *** CD-ROM | disk | FTP | other *** search
- /*
- WASTE Demo Project:
- File Handling
-
- Copyright © 1993-1995 Marco Piovanelli
- All Rights Reserved
-
- C port by John C. Daub
- */
-
-
- #ifndef __WEDEMOAPP__
- #include "WEDemoIntf.h"
- #endif
-
- #ifndef __FOLDERS__
- #include <Folders.h>
- #endif
-
- OSErr ReadTextFile( const FSSpec *pFileSpec, WEReference we )
- {
- Size textSize;
- OSErr err = noErr;
- short dataForkRefNum = 0;
- short resForkRefNum = 0;
- Handle hText = NULL;
- StScrpHandle hStyles = NULL;
- WESoupHandle hSoup = NULL;
-
- // open the data fork with read-only permission
-
- err = FSpOpenDF( pFileSpec, fsRdPerm, &dataForkRefNum );
- if ( err != noErr )
- goto cleanup;
-
- // get data fork size
-
- err = GetEOF( dataForkRefNum, &textSize );
- if ( err != noErr )
- goto cleanup;
-
- // marco didn't have this, but Michael Kamprath did...i think it's a good thing...
- // set the position in the file from where to start reading
-
- err = SetFPos( dataForkRefNum, fsFromStart, 0L );
- if ( err != noErr )
- goto cleanup;
-
- // Try to allocate a handle that large, use temporary memory if available
-
- err = NewHandleTemp( textSize, &hText );
- if ( err != noErr )
- goto cleanup;
-
-
- // read in the text
-
- HLock( hText );
- err = FSRead( dataForkRefNum, &textSize, *hText );
- HUnlock( hText );
- if ( err != noErr )
- goto cleanup;
-
- // again, something Marco didn't have, but Michael did...
- // let's close the data fork before opening up the resource fork.
-
- err = FSClose( dataForkRefNum );
- if ( err != noErr )
- goto cleanup;
-
- // see if the file has a resource fork
-
- resForkRefNum = FSpOpenResFile( pFileSpec, fsRdPerm );
- if ( resForkRefNum != -1 ) //FSpOpenResFile will return -1 if it fails
- {
- // look for a style scrap resource (get the first one; the resource ID doesn't matter)
-
- // this is something I added over Marco's code
- // this whole resource stuff is interesting. first, we could have no resource fork
- // at all (and that's easy to deal with). second, we could have a resource fork
- // and the resources we want ('styl' and 'SOUP'). but third, we could have
- // a resource fork but not the resources we want. it's simple to deal with all these
- // things, but just make sure that you do!
-
- hStyles = (StScrpHandle)Get1IndResource( kTypeStyles, 1 );
- err = ResError();
- if ( (err != noErr) && (err != resNotFound) )
- {
- hStyles = NULL;
- goto CRF;
- }
- else if ( err == resNotFound )
- {
- hStyles = NULL;
- }
- else
- DetachResource( (Handle)hStyles );
-
- // look for a soup resource as well
- hSoup = (WESoupHandle)Get1IndResource( kTypeSoup, 1 );
- err = ResError();
- if ( (err != noErr) && (err != resNotFound) )
- {
- hSoup = NULL;
- goto CRF;
- }
- else if ( err == resNotFound )
- {
- hSoup = NULL;
- }
- else
- DetachResource( (Handle)hSoup );
-
- CRF:
- CloseResFile( resForkRefNum );
- err = ResError();
- if ( err != noErr )
- goto cleanup;
-
- }
- else
- {
- // does not have resource fork, so no style or soup
-
- hStyles = NULL;
- hSoup = NULL;
- }
-
-
- // insert the text into the WE record
-
- HLock( (Handle)hStyles );
- HLock( (Handle)hSoup );
- HLock( hText );
- err = WEInsert( *hText, textSize, hStyles, hSoup, we );
- HUnlock( hText );
- HUnlock( (Handle)hStyles );
- HUnlock( (Handle)hSoup );
-
- if ( err != noErr )
- goto cleanup;
-
-
- // set the insertion point at the beginning of the text
- WESetSelection( 0, 0, we );
-
- // reset the WE instance modification count
- WEResetModCount( we );
-
- // clean up and exit
-
- cleanup:
-
- // display an alert box if anything went wrong
- if (err != noErr)
- {
- ErrorAlert( err );
- }
-
- ForgetHandle(&hText);
- ForgetHandle((Handle *) &hStyles);
- ForgetHandle((Handle *) &hSoup);
-
- if ( dataForkRefNum > 0 )
- {
- FSClose(dataForkRefNum);
- dataForkRefNum = 0;
- }
-
- if ( resForkRefNum > 0 )
- {
- CloseResFile(resForkRefNum);
- resForkRefNum = 0;
- }
-
- return noErr;
- }
-
-
- // I added a bunch of other functionality to WriteTextFile(), mostly to show how to use
- // temp files, check for locked files, etc. ( all along Apple's recommended way of
- // doing things. - JCD
-
- OSErr WriteTextFile( const FSSpec * pFileSpec, WEReference we )
- {
- FInfo fileInfo;
- Size textSize;
- Boolean replacing = false;
- OSErr err = noErr;
- short dataForkRefNum = 0;
- short resForkRefNum = 0;
- Handle hText = NULL;
- StScrpHandle hStyles = NULL;
- WESoupHandle hSoup = NULL;
- unsigned long theTime;
- Str255 tempFileName;
- FSSpec tempFileSpec;
- short tempVRef; // volume reference # for the temp file
- long tempDirID; // directory ID of the temp file
-
- // will we be replacing an existing file?
-
- err = FSpGetFInfo( pFileSpec, &fileInfo );
- if ( err == noErr )
- replacing = true;
- else if ( err == fnfErr )
- replacing = false;
- else
- {
- goto cleanup;
- }
-
- // originally, Marco had it so that if the file already existed (replacing == true)
- // then just can the original file and move along. for the scope of this demo, that
- // really is ok, but generally speaking, not the Apple-recommended way of doing things.
- // since we know we're under (at least) System 7 (due to WASTE's need of it), we know
- // we can use temporary files, so let us do so!
-
- // also, Marco didn't check for locked files (technically, if a file is locked from
- // the Finder, you shouldn't be able to modify it). let's check for that.
-
- // if the file currently exists (meaning it was saved at some time in the past, be it
- // 5 minutes ago, or 5 days ago), there is a chance that it could be locked (from the
- // Finder's "Get Info" window (or otherwise). If the file is locked, you cannot
- // save changes. Therefore, if 'replacing' is true, we have to throw up a message
- // saying that we can't do this, then exit.
-
- if ( replacing )
- {
- err = FSpCheckObjectLock( pFileSpec );
- if ( err != noErr ) // if it returns noErr, the file/directory is NOT locked
- {
- return err;
- }
- }
-
- if ( replacing )
- {
-
- // create the temporary file name. the name doesn't have to make sense, just
- // be unique
-
- GetDateTime( &theTime );
- NumToString( theTime, tempFileName );
-
- // find the temporary items folder on the file's volume; create it if necessary
- // it is important that the temp folder (and the temp file) and the "original" target
- // file be on the same volume; if not, FSpExchangeFiles will return diffVolErr (-1303)
- // and won't work
-
- err = FindFolder( pFileSpec->vRefNum, kTemporaryFolderType, kCreateFolder, &tempVRef, &tempDirID );
- if ( err != noErr )
- {
- return err; // for now, do nothing, just return
- }
-
- // make an FSSpec for the temp file
-
- err = FSMakeFSSpec( tempVRef, tempDirID, tempFileName, &tempFileSpec );
- if ( (err != noErr) && (err != fnfErr ) )
- {
- return err;
- }
-
- }
-
- // create a new file. if we're replacing, make a temp file. if it's a
- // new file from the onset, just create the file
-
- // should we allow people to choose the file to create? i.e. create a TEXT
- // file or a ttro file? if you'd like to do this, you'll want to find this
- // info out when calling CustomPutFile() and pass that info to this function
-
- if ( replacing )
- FSpCreateResFile( &tempFileSpec, 'trsh', 'trsh', smSystemScript );
- else
- FSpCreateResFile( pFileSpec, kAppSignature, kTypeText, smSystemScript );
-
- err = ResError();
- if ( err != noErr )
- {
- goto cleanup;
- }
-
- // if replacing an old file, copy the old file information
- if ( replacing )
- {
- err = FSpSetFInfo( &tempFileSpec, &fileInfo );
- if ( err != noErr )
- {
- goto cleanup;
- }
- }
-
-
- // open the data fork for writing
- if ( replacing )
- err = FSpOpenDF( &tempFileSpec, fsRdWrPerm, &dataForkRefNum );
- else
- err = FSpOpenDF( pFileSpec, fsRdWrPerm, &dataForkRefNum );
-
- if ( err != noErr )
- {
- goto cleanup;
- }
-
- // set the end-of-file
-
- err = SetEOF( dataForkRefNum, 0 );
- if ( err != noErr )
- {
- goto cleanup;
- }
-
- // set the position in the file to write from
-
- err = SetFPos( dataForkRefNum, fsFromStart, 0 );
- if ( err != noErr )
- {
- goto cleanup;
- }
-
- // get the text handle from the WE instance
- // WEGetText returns the original handle, not a copy, so don't dispose of it!!
- hText = WEGetText( we );
- textSize = GetHandleSize( hText );
-
- // write the text
- HLock( hText );
- err = FSWrite( dataForkRefNum, &textSize, *hText );
- HUnlock( hText );
-
- if ( err != noErr )
- {
- goto cleanup;
- }
-
- // open the resource file for writing
-
- if ( replacing )
- resForkRefNum = FSpOpenResFile( &tempFileSpec, fsRdWrPerm );
- else
- resForkRefNum = FSpOpenResFile( pFileSpec, fsRdWrPerm );
-
- err = ResError();
- if ( err != noErr )
- {
- goto cleanup;
- }
-
- // allocate temporary handles to hold the style scrap and the soup
- // try tapping temporary memory since WECopyRange() could get huge
-
- err = NewHandleTemp( 0, (Handle *) &hStyles );
- if ( err != noErr )
- {
- goto cleanup;
- }
-
- err = NewHandleTemp( 0, (Handle *) &hSoup );
- if ( err != noErr )
- {
- goto cleanup;
- }
-
- // create the style scrap and the soup
-
-
- err = WECopyRange( 0, LONG_MAX, NULL, hStyles, hSoup, we );
- if ( err != noErr )
- {
- goto cleanup;
- }
-
-
- // make them resource handles
-
- AddResource( (Handle)hStyles, kTypeStyles, 128, "\p" );
- err = ResError();
- if ( err != noErr )
- {
- goto cleanup;
- }
-
- AddResource( (Handle)hSoup, kTypeSoup, 128, "\p" );
- err = ResError();
- if ( err != noErr )
- {
- goto cleanup;
- }
-
- // write them to the resource file
-
- ChangedResource( (Handle)hStyles );
- WriteResource( (Handle)hStyles );
- err = ResError();
- if ( err != noErr )
- {
- goto cleanup;
- }
-
- ChangedResource( (Handle)hSoup );
- WriteResource( (Handle)hSoup );
- err = ResError();
- if ( err != noErr )
- {
- goto cleanup;
- }
-
-
-
- // "clean" this document by resetting the WE instance modification count
-
- WEResetModCount( we );
-
- err = noErr;
-
- // clean up
-
- cleanup:
-
- // display an alert box if anything went wrong
- if (err != noErr)
- {
- ErrorAlert( err );
- }
-
- // remember, don't dispose the hText handle!
-
- ForgetResource( (Handle *) &hStyles );
- ForgetResource( (Handle *) &hSoup );
-
- if ( dataForkRefNum > 0 )
- {
- FSClose( dataForkRefNum );
- dataForkRefNum = 0;
- }
-
- if ( resForkRefNum > 0 )
- {
- CloseResFile( resForkRefNum );
- resForkRefNum = 0;
- }
-
- if ( replacing )
- {
- // update the disk with any unwritten data
-
- FlushVol( "\p", tempFileSpec.vRefNum );
-
- // since we were replacing an existing file, let's now swap the original
- // and the temp file. let's hear it for safe saves.
-
- err = FSpExchangeFiles( &tempFileSpec, pFileSpec );
- if ( err != noErr )
- {
- // handle the error
-
- return err;
- }
-
- // can the temp file since we don't need it anymore
-
- err = FSpDelete( &tempFileSpec );
- if ( err != noErr )
- {
- // handle the error
-
- return err;
- }
- }
-
- // and update the disk with any unwritten data
-
- FlushVol( "\p", pFileSpec->vRefNum );
-
- return err;
-
- }
-
-
- // this simple routine is meant to give an idea of how the drag translation hook ('xdrg')
- // is supposed to work -- in the real world, I should probably handle styled text files,
- // PICT files, and maybe other fancier file types here: that is left as an exercise
- // for the reader - Marco
-
- // well, this exercise for the reader has already been done! Michael Kamprath has written a
- // series of WASTE Object Handlers. it's a nice code library that suppliments WASTE by giving
- // the programmer ready-made stuff for handling PICTs, snd 's, and HFS objects. Due to the
- // fact that this library exists, for Pascal versions of the WASTE Demo App, Marco more or less
- // translated Michael's code into Pascal and integrated them into the demo. Since the demo
- // will now be in C, I'm taking the initiative to remove Marco's old drag object handling
- // code (this function, and related object handler files, such as WEDemoSounds.p and
- // WEDemoPictures.p) and instead putting in Michael's library.
-
- pascal OSErr TranslateDrag( DragReference theDrag, ItemReference theItem, FlavorType requestedType, Handle dataHandle )
- {
- #pragma unused ( theDrag, theItem, dataHandle )
-
- OSErr err = badDragFlavorErr; // assume failure
-
- if ( requestedType != kTypeText )
- return err;
-
- if ( requestedType != kTypeTextReadOnly )
- return err;
-
- err = noErr;
-
- return err;
- }
-
-
-
-
- /* The following 2 functions (CheckObjectLock and FSpCheckObjectLock) were taken
- from MoreFiles 1.2.1, a code sample from Apple's DTS. Here's some info from
- the MoreFiles readme:
-
- A collection of File Manager and related routines
-
- by Jim Luther, Apple Macintosh Developer Technical Support
- with significant code contributions by Nitin Ganatra, Apple Macintosh Developer
- Technical Support
- MoreFile Reference is by Eric Soldan
- Copyright © 1992-1994 Apple Computer, Inc.
- All rights reserved.
-
- Frankly, this is one amazing repository of all sorts of file-related things. I'd
- check it out if you can. (should be, as of this writing, on ftp.info.apple.com
- in like the /Apple.Support.Services/Developer_Support/ or something like that).
-
- thanx to Alex Rosen for answering my post on comp.sys.mac.programmer.help and pointing
- out MoreFiles to me.
-
- WHAT DO THEY DO? Oh duh...i should tell you huh?
-
- Both functions do the same thing: check to see if the object is locked
- (in this case, the object is a file). This is using in WriteTextFile()
- to prevent overwriting/deleting locked files.
-
- The only difference between these 2 functions are the arguments passed.
- the first takes a vRefNum, dirID and a file name, the second takes an FSSpec
- and then just calls the first based on the FSSpec (just makes for slighly
- neater/readable code)
- */
-
- pascal OSErr CheckObjectLock(short vRefNum, long dirID, StringPtr name)
- {
- CInfoPBRec pb;
- OSErr error;
-
- pb.hFileInfo.ioNamePtr = name;
- pb.hFileInfo.ioVRefNum = vRefNum;
- pb.hFileInfo.ioDirID = dirID;
- pb.hFileInfo.ioFDirIndex = 0; // use ioNamePtr and ioDirID
- error = PBGetCatInfoSync(&pb);
-
- if ( error == noErr )
- {
- // check locked bit
- if ( (pb.hFileInfo.ioFlAttrib & 0x01) != 0 )
- error = fLckdErr;
- }
- return ( error );
- }
-
- /*****************************************************************************/
-
- pascal OSErr FSpCheckObjectLock(const FSSpec *spec)
- {
- return ( CheckObjectLock(spec->vRefNum, spec->parID, (StringPtr) spec->name) );
- }
-
-